from django.shortcuts import render, redirect

from django.utils.decorators import method_decorator
from django.utils.deprecation import MiddlewareMixin
# 导包
from django.http import HttpResponse, HttpResponseRedirect, JsonResponse
# 导入类视图
from django.views import View

from myapp.models import User, Goods, Cate, Comment, UserFlow
import json
from django.core.serializers import serialize
from rest_framework.response import Response
from rest_framework.views import APIView
# 导入加密库
import hashlib
# 导入图片库
# 绘画库
from PIL import ImageDraw
# 字体库
from PIL import ImageFont
# 图片库
from PIL import Image
# 随机库
import random
# 文件流
import io

import requests

# 导入上传文件夹配置
from mydjango.settings import UPLOAD_ROOT
import os

# 导入原生sql模块
from django.db import connection

import jwt

# 导入redis数据库
import redis

# 导入时间模块
import time

# 导入公共目录变量
from mydjango.settings import BASE_DIR

# 导包
from django.db.models import Q, F

import re

# 导入dwebsocket的库
from dwebsocket.decorators import accept_websocket
import uuid

# 导入序列化对象
from myapp.myser import UserSerializers, GoodsSer, CateSer, CommentSer, UserFlowSer

# 定义地址和端口
host = '127.0.0.1'
port = 6379

# 建立redis连接
r = redis.Redis(host=host, port=port)

# mongo
import pymongo

from bson import json_util as josnb

# 建立与mongo的连接
mongo_client = pymongo.MongoClient(host=host, port=27017)


# 商品检索接口
class GoodsSearch(APIView):

    def get(self, request):
        # 接收参数
        word = request.GET.get('word', None)
        # 模糊查询 管道符(|)代表or(或者)  &代表and(并且)
        goodslist = Goods.objects.filter(Q(name__contains=word) | Q(desc__icontains=word))

        # sql转译
        # select * from goods where (name like '%word%' or desc like '%word%') or (parms like '%word%')

        # 序列化
        goods_ser = GoodsSer(goodslist, many=True)
        return Response(goods_ser.data)


# 获取前n名的数据
def get_top_n(num):
    # 获取redis数据
    goods_click = r.zrange('good_rank', 0, -1, desc=True, withscores=True)[:num]
    goods = Goods.objects.in_bulk([int(item[0]) for item in goods_click])
    res = []  # 合并操作
    for item in goods_click:
        try:
            res.append({int(item[1]): goods[int(item[0])]})
        except Exception as e:
            pass
    return res


# 获取商品排名数据
class GoodsRank(APIView):

    def get(self, request):
        get_res = get_top_n(10)  # 获取排名前n的数据
        res = []
        for dic in get_res:  # 遍历进行序列化
            for k, v in dic.items():
                data = GoodsSer(v).data  # 序列化数据
                data['clicks'] = k
                res.append(data)
        return Response(res)


# 商品访问排名
class GoodsClick(APIView):

    def get(self, request):
        gid = request.GET.get('gid')
        r.zincrby('good_rank', 1, int(gid))

        print(r.zrange('good_rank', 0, -1, desc=True, withscores=True))

        return Response({
            'code': 200,
            'message': '访问+1'
        })


# 对结果集美化方法
def dictfetchall(cursor):
    # 获取游标描述
    desc = cursor.description
    return [
        dict(zip([col[0] for col in desc], row))
        for row in cursor.fetchall()
    ]


# 用户批量删除收藏
class DelFlow(APIView):

    def get(self, request):
        uid = request.GET.get('uid')
        ids = request.GET.get('ids')
        # 强转
        id_list = eval(ids)

        for i in id_list:
            flow = UserFlow.objects.get(uid=int(uid), gid=int(i))
            flow.delete()

        return Response({
            'code': 200,
            'message': '删除成功'
        })


# 查询此用户关注了哪些商品
class UidFlow(View):

    def get(self, request):
        uid = request.GET.get('uid')

        # 建立游标
        cursor = connection.cursor()

        # 执行sql语句
        cursor.execute(
            'select a.id,a.name,b.create_time from goods a left join userflow b on a.id=b.gid where b.uid = %s' % uid)

        # 获取结果
        # result = cursor.fetchall()
        result = dictfetchall(cursor)

        # 手动序列化
        return HttpResponse(json.dumps(result, ensure_ascii=False, indent=4, default=str),
                            content_type='application/json')

    def post(self, request):
        uid = request.POST.get('uid', None)
        ids = request.POST.get('ids', None)
        print(uid, ids)


# 展示哪些用户关注了此商品
class GidFlow(View):

    def get(self, request):
        gid = request.GET.get('gid')

        # 建立游标
        cursor = connection.cursor()

        # 执行sql语句
        cursor.execute('select a.username from user a left join userflow b on a.id=b.uid where b.gid = %s' % gid)

        # 获取结果
        result = cursor.fetchall()

        return HttpResponse(json.dumps(result, ensure_ascii=False, indent=4, default=str),
                            content_type='application/json')


# 判断用户是都已经收藏
class GetCollect(APIView):

    def get(self, request):
        uid = request.GET.get('uid')
        gid = request.GET.get('gid')

        collect = UserFlow.objects.filter(uid=uid, gid=gid).first()
        collects = UserFlow.objects.filter(gid=gid)
        collect_ser = UserFlowSer(collects, many=True)

        if collect:
            return Response({
                'code': 200,
                'message': '已收藏',
                'collect_ser': collect_ser.data
            })
        else:
            return Response({
                'code': 203,
                'message': '未收藏',
                'collect_ser': collect_ser.data
            })


# 用户收藏接口(添加收藏、取消收藏)
class Collect(APIView):

    # 取消收藏
    def get(self, request):
        uid = request.GET.get('uid')
        gid = request.GET.get('gid')

        collect = UserFlow.objects.filter(uid=uid, gid=gid)
        collect.delete()

        good = Goods.objects.get(id=gid)
        good.flow -= 1
        good.save()

        return Response({
            'code': 200,
            'message': '取消成功'
        })

    # 添加收藏
    def post(self, request):
        gid = request.POST.get('gid')
        uid = request.POST.get('uid')

        collect = UserFlow.objects.filter(gid=gid, uid=uid)
        if collect:
            return Response({
                'code': 403,
                'message': '收藏失败'
            })

        UserFlow.objects.create(uid=uid, gid=gid)
        good = Goods.objects.get(id=gid)
        good.flow += 1
        good.save()
        return Response({
            'code': 200,
            'message': '收藏成功'
        })


# 获取所有用户信息
class GetUser(APIView):

    def get(self, request):
        user = User.objects.filter()
        user_ser = UserSerializers(user, many=True)

        return Response(user_ser.data)


# 商品评论分页接口
class ContentList(APIView):

    def get(self, request):
        # 当前页
        page = int(request.GET.get('page', 1))
        # 一页有几条数据
        size = int(request.GET.get('size', 1))
        # 获取商品id
        gid = int(request.GET.get('gid', 1))

        # 定义从哪开始切片
        data_start = (page - 1) * size

        # 定义在哪里结束切片
        data_end = page * size

        # 查询数据
        contentlist = Comment.objects.filter(gid=gid).order_by('-id')[data_start:data_end]
        # 查询总数据量
        count = Comment.objects.count()

        # 序列化操作
        content_ser = CommentSer(contentlist, many=True)
        return Response({
            'total': count,
            'data': content_ser.data,
        })


# 获取商品的所有评论
class GetComment(APIView):

    def get(self, request):
        gid = request.GET.get('gid')
        content = Comment.objects.filter(gid=int(gid)).order_by('-id')

        comment = CommentSer(content, many=True)

        return Response(comment.data)


# 反序列化入库(商品评论)
class InsertComment(APIView):

    def post(self, request):
        # print(request.data.get('uid'))
        # print(request.POST.get('uid'))
        # print(request.data.get('content'))
        uid = request.data.get('uid')
        struid = str(uid)
        content = request.data.get('content')

        # 判断用户在规定时间内是否发表过评论
        if r.get(struid):
            return Response({
                'code': 403,
                'message': '每个用户每30秒只能评论一次哦！'
            })

        # 初始化参数
        comment = CommentSer(data=request.data)
        # print(comment)

        # 数据校验
        if comment.is_valid():
            # 数据入库
            comment.save()
            # 根据用户id存redis防止用户恶意刷评
            r.set(struid, content)
            # 设置过期时间(30秒)
            r.expire(struid, 30)

            return Response({
                'code': 200,
                'message': '评论成功'
            })

        else:
            return Response({
                'code': 203,
                'message': '逻辑有问题哦，请程序员赶快调试'
            })


class AccessRight(MiddlewareMixin):  # 中间件设置访问次数

    def process_request(self, request):
        if re.match(r'/getonline/', request.path):
            # print('匹配了路由')
            if 'HTTP_X_FORWARDED_FOR' in request.META:
                ip = request.META.get('HTTP_X_FORWARDED_FOR')
            else:
                ip = request.META.get('REMOTE_ADDR')
            if ip not in r.smembers(id):  # 判断该用户是否恶意刷新访问量
                r.sadd('online', ip)  # 保存此ip到redis中
                r.expire('online', 60)  # 时效为60秒，保存到数据库中。后期调用查看在线人数的时候，可以查看online数量即可
            else:
                return HttpResponse('哈哈')
        else:
            # print('代码执行到这里')
            pass


# 统计在线人数
class GetOnLine(APIView):

    def get(self, request):
        # 获取客户id
        # 可以获得用户的IP地址。但是有些网站服务器会使用ngix等代理http，或者是该网站做了负载均衡，
        # 导致使用remote_addr抓取到的是127.0.0.1，这时使用HTTP_X_FORWARDED_FOR才获得是用户的真实IP
        if 'HTTP_X_FORWARDED_FOR' in request.META:

            ip = request.META.get('HTTP_X_FORWARDED_FOR')

        else:

            ip = request.META.get('REMOTE_ADDR')

        # 对用户IP进行存储
        r.sadd("online", ip)

        # 设置超时时间，超时时常单位秒
        r.expire("online", 20)

        # 获取在线人数的数量
        myset = r.smembers('online')

        # 获取总访问量
        r.lpush('testlist', 1)
        mylist = r.lrange('testlist', 0, r.llen('testlist'))
        print(len(mylist))

        return Response({
            'online': len(myset),
            'ip': ip,
        })


# 获取商品标签接口
class GetTags(View):

    def get(self, request):
        id = request.GET.get('id', None)

        # 建立数据库对象
        db = mongo_client.md
        # 建立表对象
        table = db.mytag
        # 查询
        result = table.find_one({"gid": str(id)})

        # ensure_ascii=False 防止中文乱码
        josnb.dumps(result, ensure_ascii=False)

        return HttpResponse(josnb.dumps(result, ensure_ascii=False))


# 商品标签添加接口 （存redis数据库）
class InsertRedis(APIView):

    def get(self, request):
        id = request.GET.get('id', None)
        tags = request.GET.get('tags', None)
        # tag = tags.split(",")
        r.set(id, tags)

        return Response(r.get(id))


# 商品标签添加接口 （存mongo数据库）
class InsertTags(APIView):

    def get(self, request):

        id = request.GET.get('id', None)
        # tags是字符串
        tags = request.GET.get('tags', None)
        # tag是列表
        tag = tags.split(",")

        # 建立数据库对象
        db = mongo_client.md
        # 建立表对象
        table = db.mytag
        # 查询
        res = table.find({"gid": str(id)}).count()
        # 排重
        if res > 0:
            return Response({
                'code': 203,
                'message': '数据id重复'
            })
        else:
            table.insert({'gid': str(id), 'tags': tag})

            # mes = [1,2,3]
            # mess = ",".join(['%s' % mes for mes in mes])
            # # mess = 1,2,3 (字符串)
            # met = mess.split(",")
            # # met = ['1', '2', '3'] (列表中套字符串)
            # results = list(map(int, met))
            # # results = [1, 2, 3] (还原到列表中套整形)

            return Response({"message": '入库成功'})


# 修改标签接口
class UpdateTags(APIView):

    def get(self, request):
        id = request.GET.get('id', None)
        tags = request.GET.get('tags', None)
        tags = tags.split(',')

        # 连接库
        db = mongo_client.md
        # 声明操作的数据表
        table = db.mytag
        table.update({'gid': str(id)}, {"$set": {'tags': tags}})  # 修改mongo数据
        return Response({
            'code': 200,
            'message': '标签修改成功'
        })


# 商品分类接口
class CateInfo(APIView):

    def get(self, request):
        # 进行商品查询
        cate = Cate.objects.filter()

        # 进行序列化操作
        cate_ser = CateSer(cate, many=True)

        # 进行返回
        return Response(cate_ser.data)


# 商品入库接口
class AddGoods(APIView):

    def post(self, request):
        name = request.POST.get('name')
        desc = request.POST.get('desc')
        img = request.POST.get('img')
        video = request.POST.get('video')
        parms = request.POST.get('pars')
        cate = request.POST.get('cate')
        price = request.POST.get('price')
        print(name, desc, cate, price, desc, img, video)

        # 排重
        goods = Goods.objects.filter(name=name).first()

        if goods:
            return Response({
                'code': 203,
                'message': '该商品已存在，不要重复添加。'
            })

        # 进行入库
        cated = Cate.objects.filter(name=cate).first()
        print(cated)

        Goods.objects.create(name=name, desc=desc, parms=parms, cate_id=cated.pid,
                             price=price, img=img, video=video)

        good = Goods.objects.filter(name=name).first()
        return Response({
            'id': good.id,
            'code': 200,
            'message': '添加成功！'
        })


# 修改商品接口
class UpdateGoods(APIView):

    def post(self, request):
        id = int(request.POST.get('id'))
        name = request.POST.get('name')
        desc = request.POST.get('desc')
        img = request.POST.get('img')
        video = request.POST.get('video')
        parms = request.POST.get('pars')
        cate = request.POST.get('cate')
        price = request.POST.get('price')
        print(name, desc, cate, price, desc, img, video)
        # 根据id查出商品
        good = Goods.objects.filter(id=id)
        print(good)

        goods = Goods.objects.get(id=id)
        print(goods)

        goodss = Goods.objects.filter(id=id).first()

        print(goodss)

        # 获取分类表的pid
        cated = Cate.objects.filter(name=cate).first()

        # 进行修改
        good.update(name=name, desc=desc, img=img, video=video, parms=parms
                    , price=price, cate_id=cated.pid)

        return Response({
            'code': 200,
            'message': '修改成功！'
        })


# 商品列表接口
class GoodsList(APIView):

    def get(self, request):
        # 当前页
        page = int(request.GET.get('page', 1))
        # 一页有几条数据
        size = int(request.GET.get('size', 1))

        # 定义从哪开始切片
        data_start = (page - 1) * size

        # 定义在哪里结束切片
        data_end = page * size

        # 查询数据
        goodslist = Goods.objects.all()[data_start:data_end]
        # 查询总数据量
        count = Goods.objects.count()

        # 序列化操作
        goods_ser = GoodsSer(goodslist, many=True)
        return Response({
            'total': count,
            'data': goods_ser.data,
        })


# 添加分类
class AddCate(APIView):

    def get(self, request):
        name = request.GET.get('name')
        pid = request.GET.get('pid')

        cate = Cate.objects.filter(name=name).first()
        if cate:
            return Response({
                'code': 203,
                'message': '该分类已存在，不可重复添加!'
            })
        Cate.objects.create(name=name, pid=pid)
        return Response({
            'code': 200,
            'message': '分类添加成功'
        })


# 商品详情页
class GoodInfo(APIView):

    def get(self, request):
        id = int(request.GET.get('id', 0))

        good = Goods.objects.get(id=id)
        goodser = GoodsSer(good)

        return Response({
            'code': 200,
            'data': goodser.data
        })

